name: Build project

on: [push, pull_request, workflow_dispatch]

env:
  BUILD_TYPE: RelWithDebInfo
  ## For locally compiled dependencies
  INSTALL_PATH: ${{github.workspace}}/dependencies/install
  ## Temp directory for installers of the downloaded dependencies
  DOWNLOAD_PATH: ${{github.workspace}}/dependencies/download

permissions: read-all

jobs:
  ## BUILD JOBS
  build:
    strategy:
      matrix:
        db: [postgresql, sqlite3]
        os: [ubuntu-20.04, ubuntu-22.04]
      fail-fast: false

    runs-on: ${{ matrix.os }}
    outputs:
      ubuntu-20-04-compile-hash-key: ${{ steps.download-compile-dependencies.outputs.compile-hash-key }}
      ubuntu-22-04-compile-hash-key: ${{ steps.download-compile-dependencies.outputs.compile-hash-key }}

    services:
      # Label used to access the service container
      postgres:
        image: postgres
        # Provide the password for postgres
        env:
          POSTGRES_PASSWORD: postgres
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          # Maps tcp port 5432 on service container to the host
          - 5432:5432

    steps:
      - uses: actions/checkout@v3

      - name: Update apt-get
        run: sudo apt-get update

      - name: Install required packages for build
        run: ./.github/scripts/${{ matrix.os }}/setup_build.sh

      - name: Set has-compiled-dependencies flag
        id: compilation-flag
        run: |
          if [ -f ./.github/scripts/${{ matrix.os }}/compile_build.sh ]; then
            echo "HAS_COMPILED_DEPENDENCIES=true" >> "$GITHUB_ENV"
          else
            echo "HAS_COMPILED_DEPENDENCIES=false" >> "$GITHUB_ENV"
          fi

      - name: Download installers for compiled dependencies
        if: ${{ env.HAS_COMPILED_DEPENDENCIES == 'true' }}
        id: download-compile-dependencies
        run: |
          chmod +x ./.github/scripts/${{ matrix.os }}/download_build.sh
          ./.github/scripts/${{ matrix.os }}/download_build.sh

      - name: Restore compiled dependencies
        id: restore-compiled-dependencies
        uses: actions/cache/restore@v3
        with:
          path: ${{ env.INSTALL_PATH }}
          key: ${{ matrix.os }}-compile-install-${{ env.CACHE_KEY }}

      - name: Compile dependencies
        if: ${{ env.HAS_COMPILED_DEPENDENCIES == 'true' && steps.restore-compiled-dependencies.outputs.cache-hit != 'true' }}
        run: |
          chmod +x ./.github/scripts/${{ matrix.os }}/compile_build.sh
          ./.github/scripts/${{ matrix.os }}/compile_build.sh

      - name: Post compilation configuration (build)
        if: ${{ env.HAS_COMPILED_DEPENDENCIES == 'true' }} 
        run: |
          if [ -f ./.github/scripts/${{ matrix.os }}/postcompile_build.sh ]; then
           chmod +x ./.github/scripts/${{ matrix.os }}/postcompile_build.sh
           ./.github/scripts/${{ matrix.os }}/postcompile_build.sh
          fi

      - name: Save dependencies
        if: ${{ env.HAS_COMPILED_DEPENDENCIES == 'true' && steps.restore-compiled-dependencies.outputs.cache-hit != 'true' }} 
        id: save-compiled-dependencies
        uses: actions/cache/save@v3
        with:
          path: ${{ env.INSTALL_PATH }}
          key: ${{ matrix.os }}-compile-install-${{ env.CACHE_KEY }}

      - name: Install database packages
        run: ./.github/scripts/${{ matrix.os }}/setup_${{matrix.db}}.sh

      - name: Install GoogleTest
        run: |
          echo $PATH
          cd $HOME
          mkdir gtest
          cp -R /usr/src/googletest/* ./gtest

          cd gtest
          mkdir build
          cd build

          cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/gtest-install
          make install -j $(nproc)
          echo "GTEST_ROOT=$HOME/gtest-install" >> $GITHUB_ENV

      - name: Environment setup (Postgresql)
        if: ${{ matrix.db == 'postgresql' }}
        run: |
          echo "DB_TYPE=pgsql" >> $GITHUB_ENV
          echo "DB_CONNSTRING=pgsql:host=localhost;username=postgres;password=postgres;port=5432;database=cc_test" >> $GITHUB_ENV

      - name: Environment setup (Sqlite3)
        if: ${{ matrix.db == 'sqlite3' }}
        run: |
          echo "DB_TYPE=sqlite" >> $GITHUB_ENV
          echo "DB_CONNSTRING=sqlite:database=$HOME/mydatabase.sqlite" >> $GITHUB_ENV

      - name: Configure CMake
        working-directory: ${{github.workspace}}
        run: cmake -E make_directory $HOME/cc-build

      - name: Run CMake
        run: >
          cd $HOME/cc-build &&
          cmake ${{github.workspace}} -DCMAKE_EXPORT_COMPILE_COMMANDS=1
          -DCMAKE_INSTALL_PREFIX=$HOME/${{ matrix.os }}/${{ matrix.db }}/cc-install
          -DDATABASE=$DB_TYPE
          -DCMAKE_BUILD_TYPE=$BUILD_TYPE
          -DLLVM_DIR=/usr/lib/llvm-11/cmake
          -DClang_DIR=/usr/lib/cmake/clang-11
          -DTEST_DB=$DB_CONNSTRING

      - name: Build
        run: |
          cd $HOME/cc-build
          make -j $(nproc)

      - name: Install
        run: |
          cd $HOME/cc-build
          make install

      - name: Run tests
        run: |
          cd $HOME/cc-build
          make test ARGS=-V

      - name: Archive CodeCompass artifacts
        run: |
          mkdir ${{github.workspace}}/artifacts
          cd $HOME/${{ matrix.os }}/${{ matrix.db }}/cc-install
          zip -rq ${{github.workspace}}/artifacts/codecompass-${{ matrix.os }}-${{ matrix.db }}-bin.zip .
          cd $HOME/cc-build
          zip -Rq ${{github.workspace}}/artifacts/codecompass-${{ matrix.os }}-${{ matrix.db }}-compiletime.zip *.c *.h *.cpp *.hpp *.cxx *.hxx *.ixx *.js compile_commands.json

      - name: Upload CodeCompass binaries
        uses: actions/upload-artifact@v2
        with:
          name: codecompass-${{ matrix.os }}-${{ matrix.db }}-bin
          path: ${{github.workspace}}/artifacts/codecompass-${{ matrix.os }}-${{ matrix.db }}-bin.zip

      - name: Upload CodeCompass compile-time source files
        uses: actions/upload-artifact@v2
        with:
          name: codecompass-${{ matrix.os }}-${{ matrix.db }}-compiletime
          path: ${{github.workspace}}/artifacts/codecompass-${{ matrix.os }}-${{ matrix.db }}-compiletime.zip

  ## PARSING JOBS
  parse:
    needs: build
    strategy:
      matrix:
        db: [postgresql, sqlite3]
        os: [ubuntu-20.04, ubuntu-22.04]
      fail-fast: false

    runs-on: ${{ matrix.os }}

    services:
      # Label used to access the service container
      postgres:
        image: postgres
        # Provide the password for postgres
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
        # Set health checks to wait until postgres has started & increase SHM size
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
          --shm-size=2gb
        ports:
          # Maps tcp port 5432 on service container to the host
          - 5432:5432

    steps:
      - uses: actions/checkout@v3

      - name: Update apt-get
        run: sudo apt-get update

      # We need build dependencies for CodeCompass, as it will parsed as well
      - name: Install required packages for build
        run: ./.github/scripts/${{ matrix.os }}/setup_build.sh

      - name: Install database packages
        run: ./.github/scripts/${{ matrix.os }}/setup_${{matrix.db}}.sh

      - name: Set has-compiled-dependencies flag
        id: compilation-flag
        run: |
          if [ -f ./.github/scripts/${{ matrix.os }}/compile_build.sh ]; then
            echo "HAS_COMPILED_DEPENDENCIES=true" >> "$GITHUB_ENV"
          else
            echo "HAS_COMPILED_DEPENDENCIES=false" >> "$GITHUB_ENV"
          fi

      - name: Restore compiled dependencies
        if: ${{ env.HAS_COMPILED_DEPENDENCIES == 'true' }}
        id: restore-compiled-dependencies
        uses: actions/cache/restore@v3
        with:
          path: ${{ env.INSTALL_PATH }}
          fail-on-cache-miss: true
          key: ${{ matrix.os }}-compile-install-${{ needs.build.outputs.ubuntu-20-04-compile-hash-key }}
          restore-keys: |
            ${{ matrix.os }}-compile-install-${{ needs.build.outputs.ubuntu-20-04-compile-hash-key }}
            ${{ matrix.os }}-compile-install-${{ needs.build.outputs.ubuntu-22-04-compile-hash-key }}

      - name: Download CodeCompass binaries
        uses: actions/download-artifact@v2
        with:
          name: codecompass-${{ matrix.os }}-${{ matrix.db }}-bin
          path: ${{github.workspace}}/artifacts

      - name: Download CodeCompass compile-time source files
        uses: actions/download-artifact@v2
        with:
          name: codecompass-${{ matrix.os }}-${{ matrix.db }}-compiletime
          path: ${{github.workspace}}/artifacts

      - name: Unpack CodeCompass artifacts
        run: |
          mkdir $HOME/cc-install && cd $HOME/cc-install
          unzip -oq ${{github.workspace}}/artifacts/codecompass-${{ matrix.os }}-${{ matrix.db }}-bin.zip
          mkdir $HOME/cc-build && cd $HOME/cc-build
          unzip -oq ${{github.workspace}}/artifacts/codecompass-${{ matrix.os }}-${{ matrix.db }}-compiletime.zip

      - name: Add execute right to parser and move source files
        run: |
          chmod +x $HOME/cc-install/bin/CodeCompass_parser

      - name: Environment setup (Postgresql)
        if: ${{ matrix.db == 'postgresql' }}
        run: |
          echo "DIR_WS=ws_pgsql" >> $GITHUB_ENV
          echo "PROJ_TINYXML_CONNSTRING=pgsql:host=localhost;port=5432;user=postgres;password=postgres;database=tinyxml2" >> $GITHUB_ENV
          echo "PROJ_CODECOMPASS_CONNSTRING=pgsql:host=localhost;port=5432;user=postgres;password=postgres;database=codecompass" >> $GITHUB_ENV
          echo "PROJ_XERCES_CONNSTRING=pgsql:host=localhost;port=5432;user=postgres;password=postgres;database=xerces_c" >> $GITHUB_ENV

      - name: Environment setup (Sqlite3)
        if: ${{ matrix.db == 'sqlite3' }}
        run: |
          echo "DIR_WS=ws_sqlite3" >> $GITHUB_ENV
          echo "PROJ_TINYXML_CONNSTRING=sqlite:database=$HOME/tinyxml2.sqlite" >> $GITHUB_ENV
          echo "PROJ_CODECOMPASS_CONNSTRING=sqlite:database=$HOME/codecompass.sqlite" >> $GITHUB_ENV
          echo "PROJ_XERCES_CONNSTRING=sqlite:database=$HOME/xerces.sqlite" >> $GITHUB_ENV

      # Parsing projects
      - name: Parse TinyXML
        run: |
          cd $HOME
          git clone https://github.com/leethomason/tinyxml2
          mkdir build_tinyxml2 && cd build_tinyxml2
          cmake $HOME/tinyxml2 -DCMAKE_EXPORT_COMPILE_COMMANDS=1
          make -j $(nproc)
          cd $HOME/cc-install/bin
          ./CodeCompass_parser -d $PROJ_TINYXML_CONNSTRING -w $HOME/$DIR_WS/ -n TinyXML2 -i $HOME/tinyxml2 -i $HOME/build_tinyxml2/compile_commands.json -j $(nproc)

      - name: Parse CodeCompass
        run: >
          $HOME/cc-install/bin/CodeCompass_parser
          -d $PROJ_CODECOMPASS_CONNSTRING
          -w $HOME/$DIR_WS/
          -n "CodeCompass"
          -i ${{github.workspace}}
          -i $HOME/cc-build/compile_commands.json
          -j $(nproc)

      - name: Parse Xerces-C
        run: |
          cd $HOME
          git clone https://github.com/apache/xerces-c/
          mkdir build_xerces-c && cd build_xerces-c
          cmake $HOME/xerces-c -DCMAKE_EXPORT_COMPILE_COMMANDS=1
          make -j $(nproc)
          cd $HOME/cc-install/bin
          ./CodeCompass_parser -d $PROJ_XERCES_CONNSTRING -w $HOME/$DIR_WS/ -n "Xerces-C" -i $HOME/xerces-c -i $HOME/build_xerces-c/compile_commands.json -j $(nproc)

  ## DOCKER IMAGE JOB
  docker:
    needs: parse
    if: ${{ github.repository == 'Ericsson/CodeCompass' && (github.ref_name == 'master' || startsWith(github.ref_name, 'release/') == true) }}
    uses: ./.github/workflows/docker.yml
    with:
      tag-latest: ${{ github.ref_name == 'master' }}
    secrets:
      DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
      DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}

  ## TARBALL JOB
  tarball:
    needs: parse
    if: ${{ github.repository == 'Ericsson/CodeCompass' && (github.ref_name == 'master' || startsWith(github.ref_name, 'release/') == true) }}
    uses: ./.github/workflows/tarball.yml
    secrets:
      GITLAB_TRIGGER_TOKEN: ${{ secrets.GITLAB_TRIGGER_TOKEN }}
